Rust Tricks

2024-06-09

最后编辑于:2024-06-12

    #Rust

Rust Tricks

内存管理

当你用手动使用数组管理一块连续内存时,需要对外提供访问接口,其数据类型还是用户自定义的。

比如说这样一个4KB的内存空间,这里通常用u8,即以字节为单位

const CHUNCK_SIZE: usize = 0x4000;
struct Chunck {
	data: [u8; CHUNCK_SIZE],
}

为了提供对任意位置的访问,需要拿到指定偏移处的指针

impl Chunck {
	fn addr_of_offset(&self, offset: usize) -> usize {
		&self.data[offset] as *const _  as usize
	}
}

很直观,无需多言

然后提供任意内存结构的读取,将拿到的指针转换为对应类型的指针

impl Chunck {
	pub fn get_ref<T>(&self, offset: usize) -> &T {
		let type_size = core::mem::size_of::<T>();
		assert!(offset + type_size <= CHUCK_SIZE);
		let addr = self.addr_of_offset(offset);
		unsafe { &*(addr as *const T) }
	}
	
	pub fn get_mut<T>(&mut self, offset: usize) -> &mut T {
		let type_size = core::mem::size_of::<T>();
		assert!(offset + type_size <= CHUCK_SIZE);
		let addr = self.addr_of_offset(offset);
		unsafe { &mut *(addr as *mut T) }
	}
}

这里注意解引用裸指针是unsafe

进一步封装访问接口

pub fn read<T, V>(&self, offset: usize, f: impl FnOnce(&T) -> V) -> V {
	f(self.get_ref(offset))
}
    
pub fn modify<T, V>(&mut self, offset: usize, f: impl FnOnce(&mut T) -> V) -> V {
	f(self.get_mut(offset))
}

用例:

pub struct SuperBlock {
    magic: usize,
    pub inodes_start: usize,
}

fn main() {
    let chunck = Chunck::new();
    
    let value = chunck.read(12, |block: &SuperBlock| {
       block.inodes_start 
    });

    println!("inodes start at {:#08x}", value);
}